/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package grex;

import grex.genes.Gene;
import grex.genes.GeneException;
import grex.genes.If;

import java.util.ArrayList;

/**
 *
 * @author RIK
 */
public class TreeComparator{

    ArrayList<GP> winners;
    ArrayList<ArrayList<GP>> foldWinners = new ArrayList<ArrayList<GP>>();
    private ArrayList<ArrayList<GP>> treeGroups = new ArrayList<ArrayList<GP>>();
    ArrayList<ArrayList<GP>> predictionGroups = new ArrayList<ArrayList<GP>>();
    GP benchmarkGP=null;
    public TreeComparator() {
    }

    public TreeComparator(ArrayList<GP> trees) {
        winners = trees;//getUniquePartitios(trees);//remove duplicate prediction and then do everything again :-)
        predictionGroups = getPredictionGroups(winners);
        GP gp = predictionGroups.get(0).get(0);
        /*for(Prediction p: gp.getPcTrain().values()){
            for(ArrayList<GP> pg: predictionGroups){
                System.out.print(pg.get(0).getPcTrain().get(p.getInstance()).getPrediction() + " ");
            }
            System.out.println("");
        }//*/
        treeGroups = getSplitGroups(winners);        
    }
    public TreeComparator(ArrayList<GP> trees,GP benchmarkGP) {
        this(trees);
        this.benchmarkGP = benchmarkGP;
    }

    public void winTieLoss(GP winGP,GP compGP, double[][] outResult) throws GeneException{
        int TRAIN = 0, TEST = 1, WIN = 0, TIE = 1, LOSS = 2;
        if(outResult == null)
            outResult = new double[2][3];
        if(winGP.getTrainAccError()>compGP.getTrainAccError())
            outResult[TRAIN][WIN]+=1;
        else if(winGP.getTrainAccError()==compGP.getTrainAccError())
            outResult[TRAIN][TIE]+=1;
        else if(winGP.getTrainAccError()<compGP.getTrainAccError())
            outResult[TRAIN][LOSS]+=1;

        if(winGP.getTestAccError()>compGP.getTestAccError())
            outResult[TEST][WIN]+=1;
        else if(winGP.getTestAccError()==compGP.getTestAccError())
            outResult[TEST][TIE]+=1;
        else if(winGP.getTestAccError()<compGP.getTestAccError())
            outResult[TEST][LOSS]+=1;
    }

    public void winTieLoss(GP winGP,ArrayList<GP> group, double[][] outResult) throws GeneException{
        double groupTrainAcc = groupAvgTrainACC(group);
        double groupTestAcc = groupAvgTestACC(group);
            int TRAIN = 0, TEST = 1, WIN = 0, TIE = 1, LOSS = 2;
        if(outResult == null)
            outResult = new double[2][3];
        if(winGP.getTrainAccError()>groupTrainAcc)
            outResult[TRAIN][WIN]+=1;
        else if(winGP.getTrainAccError()==groupTrainAcc)
            outResult[TRAIN][TIE]+=1;
        else if(winGP.getTrainAccError()<groupTrainAcc)
            outResult[TRAIN][LOSS]+=1;

        if(winGP.getTestAccError()>groupTestAcc)
            outResult[TEST][WIN]+=1;
        else if(winGP.getTestAccError()==groupTestAcc)
            outResult[TEST][TIE]+=1;
        else if(winGP.getTestAccError()<groupTestAcc)
            outResult[TEST][LOSS]+=1;
    }


    public ArrayList<ArrayList<GP>> getSplitGroups(ArrayList<GP> trees) {
        ArrayList<ArrayList<GP>> splitGroups = new ArrayList<ArrayList<GP>>();
        for (GP gp : trees) {
            ArrayList<GP> group = null;
            for (ArrayList<GP> list : splitGroups) {
                if (list.get(0).getHead().equals(gp.getHead())) {
                    group = list;
                    break;
                }
            }

            if (group == null) {
                group = new ArrayList<GP>();
                splitGroups.add(group);
            }
            group.add(gp);
        }
        return splitGroups;
    }

        public ArrayList<ArrayList<GP>> getPredictionGroups(ArrayList<GP> trees) {
        ArrayList<ArrayList<GP>> predGroup = new ArrayList<ArrayList<GP>>();
        for (GP gp : trees) {
            ArrayList<GP> group = null;
            for (ArrayList<GP> list : predGroup) {
                if (equalPredictions(list.get(0),gp)) {
                    group = list;
                    break;
                }
            }
            if (group == null) {
                group = new ArrayList<GP>();
                predGroup.add(group);
            }
            group.add(gp);
        }
        return predGroup;
    }


    public ArrayList<GP> getUniquePartitios(ArrayList<GP> winnersWithDuplicates) {
        ArrayList<GP> trees = new ArrayList<GP>();
        ArrayList<GP> gps = (ArrayList<GP>) winnersWithDuplicates.clone();
        while (gps.size() > 0) {
            GP gp = gps.get(0);
            trees.add(gp);
            gps.remove(gp);
            for (int j = 0; j < gps.size(); j++) {
                GP gp2 = gps.get(j);
                if (equalPartitions(gp, gp2)) {
                    gps.remove(gp2);
                    j--;
                }
            }
        }
        return trees;
    }

    private boolean equalPartitions(GP gp1, GP gp2) {
        ArrayList<Gene> predictors1 = new ArrayList<Gene>();
        ArrayList<Gene> predictors2 = new ArrayList<Gene>();
        PredictionContainer pc1 = gp1.getPcTrain();
        PredictionContainer pc2 = gp2.getPcTrain();
        for (Prediction p : pc1.values()) {
            Gene gene1 = p.getGene();
            Gene gene2 = pc2.get(p.getInstance()).getGene();
            int predictorIndex = predictors1.indexOf(gene1);

            if (predictorIndex != -1) {//Predictor exists
                if (!gene2.equals(predictors2.get(predictorIndex))) //if gp2 uses new predictor the trees are not eqaul.
                {
                    return false;
                }
            } else {//New prediction by gp1
                if (predictors2.contains(gene2)) //gp2 has used this  gene before but ita new for gp1 = not equal trees!
                {
                    return false;
                }
                predictors1.add(p.getGene());
                predictors2.add(gene2);
            }
        }
        return true;
    }

    private boolean equalPredictions(GP gp1, GP gp2) {
        PredictionContainer pc1 = gp1.getPcTrain();
        PredictionContainer pc2 = gp2.getPcTrain();
        for (Prediction p : pc1.values()) {
            if (p.getPrediction() != pc2.get(p.getInstance()).getPrediction()) {
                return false;
            }
        }
        return true;
    }



    private int maxEquality(GP gp, ArrayList<GP> treeGroup) {
        int maxSim = 0;
        for (GP igp : treeGroup) {
            if (igp != gp) {
                int treeSim = equality(gp.getHead(), igp.getHead());
                if (treeSim > maxSim) {
                    maxSim = treeSim;
                }
                if (treeSim == gp.calcIFs() || treeSim == igp.calcIFs()) {
                    //System.out.println("Identical tree!");
                    return gp.calcIFs();
                }
            }
        }
        return maxSim;
    }

    private double groupEquality(GP gp, ArrayList<GP> treeGroup) {
        if(treeGroup == null || gp==null)
           return -1;
    	double sim = 0;
        for (GP igp : treeGroup) {
            if (igp != gp) {
                sim += equality(gp.getHead(), igp.getHead());
            }
        }
        return sim;
    }

     public double groupAvgEquality(GP gp, ArrayList<GP> treeGroup) {
    	if(treeGroup.size()<=1)
            return 0;
         double sim = groupEquality(gp, treeGroup);
        return sim/(treeGroup.size()-1);
    }





    public GP getBestAccTree(ArrayList<GP> treeGroup){
        GP bestGP = treeGroup.get(0);
        try {
            double bestAcc = bestGP.getTrainAccError();
            for(int i = 1; i < treeGroup.size();i++){
                    GP gp  = treeGroup.get(i);
                    double acc = gp.getTrainAccError();
                    if(acc > bestAcc){
                        bestAcc = acc;
                        bestGP = gp;
                    }
            }
        } catch (GeneException ex) {
            ex.printStackTrace();

        }
        return bestGP;
    }

    public GP getTypicalStructureTree(ArrayList<GP> treeGroup) {
        double maxEquality = -1, eq;
        GP maxGP = null;
        if(treeGroup.size()==1)
            return treeGroup.get(0);
        for (GP igp : treeGroup) {
            eq = groupEquality(igp, treeGroup);
            if (maxEquality < eq) {
                maxEquality = eq;
                maxGP = igp;
            }
        }
        return maxGP;
    }
     public GP getTestTypicalPredictionTree(ArrayList<GP> treeGroup) {
    	double maxEquality = 0, eq;
        GP maxGP = null;
        if(treeGroup.size()==1)
            return treeGroup.get(0);
        double[] ensemblePreds = ensembleTestPrediction(treeGroup);
        for (GP igp : treeGroup) {
            eq = predictionLikeness(igp.getOrderedTest(), ensemblePreds);
      //      System.out.println("EQ:" + eq);
            if (maxEquality < eq) {
                maxEquality = eq;
                maxGP = igp;
            }
        }
         System.out.println("MaxEq" + maxGP);
        return maxGP;
    }

    public GP getTypicalPredictionTree(ArrayList<GP> treeGroup) {
    	double maxEquality = 0, eq;
        GP maxGP = null;
        if(treeGroup.size()==1)
            return treeGroup.get(0);
        double[] ensemblePreds = ensemblePrediction(treeGroup);
        for (GP igp : treeGroup) {
            eq = predictionLikeness(igp.getOrderedTrain(), ensemblePreds);
            if (maxEquality < eq) {
                maxEquality = eq;
                maxGP = igp;
            }
        }
        return maxGP;
    }
public GP getGBLTypicalPredictionTree(ArrayList<GP> treeGroup, ArrayList<GP> all) {
    	double maxEquality = 0, eq;
        GP maxGP = null;
        if(treeGroup.size()==1)
            return treeGroup.get(0);
        double[] ensemblePreds = ensemblePrediction(all);
        for (GP igp : treeGroup) {
           
                igp.execute(igp.getPcTrain());
            eq = predictionLikeness(igp.getOrderedTrain(), ensemblePreds);
            if (maxEquality < eq) {
                maxEquality = eq;
                maxGP = igp;
            }
        }
        return maxGP;
    }
    public GP getGBLTestTypicalPredictionTree(ArrayList<GP> treeGroup, ArrayList<GP> all) {
    	double maxEquality = 0, eq;
        GP maxGP = null;
        if(treeGroup.size()==1)
            return treeGroup.get(0);
        double[] ensemblePreds = ensembleTestPrediction(all);
        for (GP igp : treeGroup) {
                igp.execute(igp.getPcTest());
            eq = predictionLikeness(igp.getOrderedTest(), ensemblePreds);
      //      System.out.println("EQ:" + eq);
            if (maxEquality < eq) {
                maxEquality = eq;
                maxGP = igp;
            }
        }
  //       System.out.println("MaxEq" + maxGP);
        return maxGP;
    }

    public double predictionLikeness(ArrayList<Prediction> preds, double[] ensPreds){
        double likeness = 0;
        for(int i=0; i < preds.size();i++){
            if(preds.get(i).getPrediction()==ensPreds[i])
                likeness += 1.0;
        }
        
        return likeness/preds.size();
    }

    public double[] ensemblePrediction(ArrayList<GP> treeGroup) {
            GP gp = treeGroup.get(0);
            gp.execute(gp.getPcTrain());
            int categories = gp.getEnvironment().getNrOfTargetCategories();
            ArrayList<Prediction> preds = gp.getOrderedTrain();
            double[][] votes = new double[preds.size()][categories];
            for (GP igp : treeGroup) {
                igp.execute(igp.getPcTrain());
                preds = igp.getOrderedTrain();
                for (int i = 0; i < preds.size(); i++) {
                    votes[i][(int) preds.get(i).getPrediction()]++;
                }
            }
            double[] majority = new double[preds.size()];
            for (int i = 0; i < votes.length; i++) {
                double max = 0;
                double maxC = 0;
                for (int c = 0; c < categories; c++) {
                    if (votes[i][c] > max) {
                        max = votes[i][c];
                        maxC = c;
                    }
                }
                majority[i] = maxC;
            }
            return majority;
    }
    public double[] ensembleTestPrediction(ArrayList<GP> treeGroup) {
            GP gp = treeGroup.get(0);
            int categories = gp.getEnvironment().getNrOfTargetCategories();

            ArrayList<Prediction> preds = gp.getOrderedTest();
            double[][] votes = new double[preds.size()][categories];
            double[] majority = new double[preds.size()];
            gp.execute(gp.getPcTest());

            for (GP igp : treeGroup) {
                igp.execute(igp.getPcTest());
                preds = igp.getOrderedTest();
                for (int i = 0; i < preds.size(); i++) {
                    votes[i][(int) preds.get(i).getPrediction()]++;
                }
            }

            for (int i = 0; i < votes.length; i++) {
                double max = 0;
                double maxC = 0;
                for (int c = 0; c < categories; c++) {
                    if (votes[i][c] > max) {
                        max = votes[i][c];
                        maxC = c;
                    }
                }
                majority[i] = maxC;
            }
            return majority;
    }


    public double groupAvgTrainACC(ArrayList<GP> treeGroup) {
        double acc = 0;
        for (GP igp : treeGroup) {
            try {
                acc += igp.getTrainAccError() / treeGroup.size();
            } catch (GeneException ex) {
            	ex.printStackTrace();
            }
        }
        return acc;
    }

    public double groupAvgTestACC(ArrayList<GP> treeGroup) {
        double acc = 0;
        for (GP igp : treeGroup) {
            try {
                acc += igp.getTestAccError() / treeGroup.size();
            } catch (GeneException ex) {
            	ex.printStackTrace();
            }
        }
        return acc;
    }

    public int globalEquality(GP gp) {
        int sim = 0;
        for (GP igp : winners) {
            if (igp != gp) {
                sim += equality(gp.getHead(), igp.getHead());
            }
        }
        return sim;
    }

    private GP getMostGlobalTypicalGPinGroup(ArrayList<GP> group){
        GP best = null;
        int max = -1;
        for(GP gp : group){
            int e = globalEquality(gp);
            if(e>max){
                max=e;
                best=gp;
            }
        }
        return best;
    }

    private int equality(Gene g1, Gene g2) {
        int e = 0;
        if (g1 == null || g2 == null) {
            return 0;
        }
        if (g1 instanceof If && g2 instanceof If) {
            Gene[] children1 = g1.getChildren();
            Gene[] children2 = g2.getChildren();
            if (children1[0].equals(children2[0])) {
                e++;
            }
            e += equality(children1[1], children2[1]);
            e += equality(children1[2], children2[2]);
        }
        return e;
    }

    public String gpVsGroupStructure() {
        String s="Structure Groups Evaluated on Structure!\n";
        try {
            if(benchmarkGP!=null)
              s+= "Initil J48 tree: \n" + benchmarkGP.getFormatedTree()+"\n";
              s += "BenchGP    :"+ "\tTrain ACC:\t" + benchmarkGP.getTrainAccError() + "\tTest ACC:\t" + benchmarkGP.getTestAccError() + "\tIfs: " + benchmarkGP.calcIFs()+"\n";
              s += "AvgAcc     :" + "\tTrain ACC:\t" + groupAvgTrainACC(winners) + "\tTest ACC:\t" + groupAvgTestACC(winners) + "\n";
                GP gp = getTypicalStructureTree(winners);
              s += "TypAll     :" + "\tTrain ACC:\t" + gp.getTrainAccError() + "\tTest ACC:\t" + gp.getTestAccError() + "\n\n";
            double avgTrainWins=0;
            double typicalTrainWins  = 0;
            double avgTestWins=0;
            double typicalTestWins  = 0;
            double trainDraws=0;
            double testDraws = 0;
            double nrOfLargeGroups = 0;
            for (int i = 0; i < getTreeGroups().size(); i++) {
                ArrayList<GP> group = getTreeGroups().get(i);
                s += "Group: " + i + " " + group.size()+ " trees.\n";
                double groupTrainAcc = groupAvgTrainACC(group);
                double groupTestAcc = groupAvgTestACC(group);
               // s += "GroupAvgAcc:\tTrain ACC:\t" + groupTrainAcc  + "\tTest ACC:\t" + groupTestAcc + "\n";

                GP allT = getMostGlobalTypicalGPinGroup(group);
                double allTypTrainAcc = allT.getTrainAccError();
                double allTypTestAcc = allT.getTestAccError();
               // s += "GroupAllTyp:\tTrain ACC:\t" + allTypTrainAcc + "\tTest ACC:\t" + allTypTestAcc + "\n";

                GP typical = getTypicalStructureTree(group);
                double typicTrainAcc = typical.getTrainAccError();
                double typicTestAcc = typical.getTestAccError();
              //  s += "GroupGroupT:\tTrain ACC:\t" + typicTrainAcc + "\tTest ACC:\t" + typicTestAcc + "\n";
                if(group.size()>=3){
                	nrOfLargeGroups ++;
	                if(groupTrainAcc>typicTrainAcc)
	                	avgTrainWins++;
	                if(groupTrainAcc==typicTrainAcc)
	                	trainDraws++;
	                if(groupTrainAcc<typicTrainAcc)
	                	typicalTrainWins++;
	                if(groupTestAcc>typicTestAcc)
	                	avgTestWins++;
	                if(groupTestAcc==typicTestAcc)
	                	testDraws++;
	                if(groupTestAcc<typicTestAcc)
	                	typicalTestWins++;
	                }
       
            }
            s+="" + nrOfLargeGroups + " groups with the size > 2 was evaluated\n";
            s+="Structure group Typical Train wins/draws/losses: " + typicalTrainWins + "/" + trainDraws +"/"+avgTrainWins+"\n";
            s+="Structure group Typical Test  wins/draws/losses: " + typicalTestWins + "/" + testDraws +"/"+avgTestWins+"\n";
        } catch (GeneException ex) {
        	ex.printStackTrace();
        }
        return s;
    }

    public String gpVsGroupStructurePrediction() {
        String s="Structure Groups Evaluated on EnsemblePrediction!\n";
        try {
            if(benchmarkGP!=null)
              s += "BenchGP    :"+ "\tTrain ACC:\t" + benchmarkGP.getTrainAccError() + "\tTest ACC:\t" + benchmarkGP.getTestAccError() + "\n";
              s += "AvgAcc     :" + "\tTrain ACC:\t" + groupAvgTrainACC(winners) + "\tTest ACC:\t" + groupAvgTestACC(winners) + "\n";
                GP gp = getTypicalPredictionTree(winners);
              s += "TypAll     :" + "\tTrain ACC:\t" + gp.getTrainAccError() + "\tTest ACC:\t" + gp.getTestAccError() + "\n\n";
            double avgTrainWins=0;
            double typicalTrainWins  = 0;
            double avgTestWins=0;
            double typicalTestWins  = 0;
            double trainDraws=0;
            double testDraws = 0;
            double nrOfLargeGroups = 0;
            for (int i = 0; i < getTreeGroups().size(); i++) {
                ArrayList<GP> group = getTreeGroups().get(i);
                s += "Group: " + i + " " + group.size()+ " trees.\n";
                double groupTrainAcc = groupAvgTrainACC(group);
                double groupTestAcc = groupAvgTestACC(group);
            //    s += "GroupAvgAcc:\tTrain ACC:\t" + groupTrainAcc  + "\tTest ACC:\t" + groupTestAcc + "\n";

              /*  GP allT = getMostGlobalTypicalGPinGroup(group);
                double allTypTrainAcc = allT.getTrainAcc();
                double allTypTestAcc = allT.getTestAcc();
                s += "GroupAllTyp:\tTrain ACC:\t" + allTypTrainAcc + "\tTest ACC:\t" + allTypTestAcc + "\n";//*/

                GP typical = getTypicalPredictionTree(group);
                double typicTrainAcc = typical.getTrainAccError();
                double typicTestAcc = typical.getTestAccError();
            //    s += "GroupGroupT:\tTrain ACC:\t" + typicTrainAcc + "\tTest ACC:\t" + typicTestAcc + "\n";
                if(group.size()>=3){
                	nrOfLargeGroups ++;
	                if(groupTrainAcc>typicTrainAcc)
	                	avgTrainWins++;
	                if(groupTrainAcc==typicTrainAcc)
	                	trainDraws++;
	                if(groupTrainAcc<typicTrainAcc)
	                	typicalTrainWins++;
	                if(groupTestAcc>typicTestAcc)
	                	avgTestWins++;
	                if(groupTestAcc==typicTestAcc)
	                	testDraws++;
	                if(groupTestAcc<typicTestAcc)
	                	typicalTestWins++;
	                }
 
            }
            s+="" + nrOfLargeGroups + " groups with the size > 2 was evaluated\n";
            s+="Structure group Typical EnsemblePred Train wins/draws/losses: " + typicalTrainWins + "/" + trainDraws +"/"+avgTrainWins+"\n";
            s+="Structure group Typical EnsemblePred Test  wins/draws/losses: " + typicalTestWins + "/" + testDraws +"/"+avgTestWins+"\n";
        } catch (GeneException ex) {
        	ex.printStackTrace();
        }
        return s;
    }

    public String gpVsGroupPrediction() {
        String s="Prediction Groups Evaluated on Structure!\n";
        try {
    //          s += "BenchGP    :"+ "\tTrain ACC:\t" + benchmarkGP.getTrainAcc() + "\tTest ACC:\t" + benchmarkGP.getTestAcc() + "\n";
              s += "AvgAcc     :" + "\tTrain ACC:\t" + groupAvgTrainACC(winners) + "\tTest ACC:\t" + groupAvgTestACC(winners) + "\n";
                GP gp = getTypicalStructureTree(winners);
              s += "TypAll     :" + "\tTrain ACC:\t" + gp.getTrainAccError() + "\tTest ACC:\t" + gp.getTestAccError() + "\n\n";

              double avgTrainWins=0;
              double typicalTrainWins  = 0;
              double avgTestWins=0;
              double typicalTestWins  = 0;
              double trainDraws=0;
              double testDraws = 0;
              double nrOfLargeGroups = 0;
            for (int i = 0; i < predictionGroups.size(); i++) {
                ArrayList<GP> group = predictionGroups.get(i);
                s += "Group: " + i + " " + group.size()+ " trees.\n";
                double groupTrainAcc = groupAvgTrainACC(group);
                double groupTestAcc = groupAvgTestACC(group);
         //       s += "GroupAvgAcc:\tTrain ACC:\t" + groupAvgTrainACC(group) + "\tTest ACC:\t" + groupAvgTestACC(group) + "\n";

                GP allT = getMostGlobalTypicalGPinGroup(group);
                double allTypTrainAcc = allT.getTrainAccError();
                double allTypTestAcc = allT.getTestAccError();
        //        s += "GroupAllTyp:\tTrain ACC:\t" + allT.getTrainAcc() + "\tTest ACC:\t" + allT.getTestAcc() + "\n";

                GP typical = getTypicalStructureTree(group);
                double typicTrainAcc = typical.getTrainAccError();
                double typicTestAcc = typical.getTestAccError();
        //        s += "GroupGroupT:\tTrain ACC:\t" + typical.getTrainAcc() + "\tTest ACC:\t" + typical.getTestAcc() + "\n";

        
                if(group.size()>=3){
                	nrOfLargeGroups ++;
	                if(groupTrainAcc>typicTrainAcc)
	                	avgTrainWins++;
	                if(groupTrainAcc==typicTrainAcc)
	                	trainDraws++;
	                if(groupTrainAcc<typicTrainAcc)
	                	typicalTrainWins++;
	                if(groupTestAcc>typicTestAcc)
	                	avgTestWins++;
	                if(groupTestAcc==typicTestAcc)
	                	testDraws++;
	                if(groupTestAcc<typicTestAcc)
	                	typicalTestWins++;
	                }
        
            }
            s+="" + nrOfLargeGroups + " groups with the size > 2 was evaluated\n";
            s+="Prediction group Typical Train wins/draws/losses: " + typicalTrainWins + "/" + trainDraws +"/"+avgTrainWins+"\n";
            s+="Prediction group Typical Test  wins/draws/losses: " + typicalTestWins + "/" + testDraws +"/"+avgTestWins+"\n";
        } catch (GeneException ex) {
        	System.out.println(ex.getStackTrace());
        	ex.printStackTrace();
        }
        return s;
    }

    @Override
    public String toString() {
        String s = statsToString();
        s += gpStatsToString();
        for (int i = 0; i < getTreeGroups().size(); i++) {
            s += "\n\n----------------Group " + i + "----------------\n";
            for (GP gp : getTreeGroups().get(i)) {
                try {
                    s += "Train ACC:" + gp.getTrainAccError() + "\tTestAcc:"
                            + gp.getTestAccError() + "\tMaxGlobalLikness:" + gp.getLikness() + "\tTotalGlobalLikness" + globalEquality(gp) + "\tMaxGroupLikness:" + maxEquality(gp, getTreeGroups().get(i)) + "\ttotalGroupLikness:" + groupEquality(gp, getTreeGroups().get(i));
                    s += gp.getFormatedTree() + "\n\n";
                } catch (GeneException ex) {
                	ex.printStackTrace();
                }
            }
        }
        
        return s;
    }

    public String predToString() {
        String s = predStatsToString();
        s += predStatsToString();

        for (int i = 0; i < predictionGroups.size(); i++) {
            s += "\n\n----------------Group " + i + "----------------\n";
            for (GP gp : predictionGroups.get(i)) {
                try {
                    s += "Train ACC:" + gp.getTrainAccError() + "\tTestAcc:"
                            + gp.getTestAccError() + "\tMaxGlobalLikness:" + gp.getLikness() + "\tTotalGlobalLikness" + globalEquality(gp) + "\tMaxGroupLikness:" + maxEquality(gp, predictionGroups.get(i)) + "\ttotalGroupLikness:" + groupEquality(gp, predictionGroups.get(i));
                    s += gp.getFormatedTree() + "\n";
                    s += gp.getGPTrainPrediction() + "\n";
                } catch (GeneException ex) {
                	ex.printStackTrace();
                }
            }
        }
        
        return s;
    }

    public String gpStatsToString() {
        String s = "";
        s += "StructureGroup:"
                + "\tPredictionGroup"
                + "\tMaxGlobalLikness:"
                + "\tTotalGlobalLikness"
                + "\tAllAvgTrainAcc"
                + "\tAllAvgTestAcc"
                + "\tStructureMaxGroupLikness:"
                + "\tStructureTotalGroupLikness:"
                + "\tStructureGroupAVGTrainAcc"
                + "\tStructureGroupAVGTestAcc"
                + "\tPredictionMaxGroupLikness:"
                + "\tPredictionTotalGroupLikness:"
                + "\tPredictionGroupAVGTrainAcc"
                + "\tPredictionGroupAVGTestAcc"
                + "\tTrainACC:"
                + "\tTestAcc:" + "\n";
        for (int sGroup = 0; sGroup < getTreeGroups().size(); sGroup++) {
            for (GP gp : getTreeGroups().get(sGroup)) {
                try {
                    double ifs = gp.calcIFs();
                    int pGroup  =0 ;
                    for(pGroup = 0;pGroup< predictionGroups.size();pGroup++){
                        if(predictionGroups.get(pGroup).contains(gp))
                            break;
                    }

                    s += sGroup + "\t" + pGroup
                            + "\t" + gp.getLikness() / ifs
                            + "\t" + globalEquality(gp) / ifs
                            + "\t" + groupAvgTrainACC(winners)
                            + "\t" + groupAvgTestACC(winners) 
                            + "\t" + maxEquality(gp, getTreeGroups().get(sGroup)) / ifs
                            + "\t" + groupEquality(gp, getTreeGroups().get(sGroup)) / ifs
                            + "\t" + groupAvgTrainACC(getTreeGroups().get(sGroup))
                            + "\t" + groupAvgTestACC(getTreeGroups().get(sGroup))
                            + "\t" + maxEquality(gp, predictionGroups.get(pGroup)) / ifs
                            + "\t" + groupEquality(gp, predictionGroups.get(pGroup)) / ifs
                            + "\t" + groupAvgTrainACC(predictionGroups.get(pGroup))
                            + "\t" + groupAvgTestACC(predictionGroups.get(pGroup))
                            + "\t" + gp.getTrainAccError()
                            + "\t" + gp.getTestAccError() + "\n";
                } catch (GeneException ex) {
                	ex.printStackTrace();
                }
            }
        }
        return s;
    }

    public String statsToString() {
        String s = "";
        s += getTreeGroups().size() + " Groups \t";
        for (int i = 0; i < getTreeGroups().size(); i++) {
            s += "\nGroup" + i + " Members" + getTreeGroups().get(i).size();
        }
        return s;
    }

    public String predStatsToString() {
        String s = "";
        s += predictionGroups.size() + " Groups \t";
        for (int i = 0; i < predictionGroups.size(); i++) {
            s += "\nGroup" + i + " Members" + predictionGroups.get(i).size();
        }
        return s;
    }

    public String calcGroupAccStatistics() {
        String s = "";
        for (ArrayList<GP> group : getTreeGroups()) {
            double maxGLikness = 0, maxTrainAcc = 0;
            GP glGP, trGP;
            for (GP gp : group) {
                try {
                    if (gp.getTrainAccError() > maxTrainAcc) {
                        maxTrainAcc = gp.getTrainAccError();
                        trGP = gp;
                    }
                    double likness = groupEquality(gp, group) / gp.calcIFs();
                    if (likness > maxGLikness) {
                        maxGLikness = likness;
                        trGP = gp;
                    }


                } catch (GeneException ex) {
                	ex.printStackTrace();
                }
            }
        }
        return s;
    }

    public void evolutionStarted(EvolutionProcess source) {
    }

    public void generationTerminated(EvolutionProcess source) {
    }

    public void batchTerminated(EvolutionProcess source) {
    }

    public void evolutionTerminated(EvolutionProcess source) {
        if (source.getOptions().getWinners() != null) {
            foldWinners.add(new ArrayList(source.getOptions().getWinners()));
        }
    }

    public void evolutionProcessTerminated(EvolutionProcess source) {
    }

    /**
     * @return the uniquePredTrees
     */
    public ArrayList<GP> getUniquePartitions() {
        return getUniquePartitios(winners);
    }

    /**
     * @param uniquePredTrees the uniquePredTrees to set
     */

    /**
     * @return the treeGroups
     */
    public ArrayList<ArrayList<GP>> getTreeGroups() {
        return treeGroups;
    }
}
